// Copyright (c) 2020 Presto Labs Pte. Ltd.
// Author: daniel

#include "coin2/exchange/base/order/fix_trade_client_mgr.h"

#include <fstream>
#include <utility>

#include <glog/logging.h>
#include <nlohmann/json.hpp>

#include "coin/proto/coin_order_enums.pb.h"
#include "coin2/exchange/base/market/market_exchange_api.h"
#include "coin2/exchange/bitstamp/api_order/fix/fix_trade_client.h"
#ifdef DISABLE_REACTOR_INTEGRATION
#include "coin2/exchange/deribit_base/api_order/fix/fix_trade_client.h"
#else
#include "coin2/exchange/deribit_base/api_order/fix/fix_trade_client2.h"
#endif
#include "coin2/exchange/ftx_common/api_order/fix/fix_trade_client.h"
#include "coin2/exchange/gdax/api_order/fix/fix_trade_client.h"
#include "coin2/exchange/lmax_digital/api_order/fix/fix_trade_client.h"
#include "coin2/exchange/order/connection.pb.h"

namespace coin2::exchange::base::order {

bool FixTradeClientMgr::Enabled(const MarketExchangeApi& mea) {
  using ClientProtocol = coin::proto::OrderGatewayClientProtocol;

  std::ifstream ifs("data/coin2/order/og_info.json");
  nlohmann::json jf = nlohmann::json::parse(ifs);
  if (jf.find(mea.String()) == jf.end()) {
    return false;
  }
  auto data = jf[mea.String()];
  if (data.find("order_gateway_client_protocol") == data.end()) {
    return false;
  }
  for (auto protocol_str : data["order_gateway_client_protocol"]) {
    ClientProtocol protocol;
    CHECK(OrderGatewayClientProtocol_Parse(protocol_str, &protocol))
        << "unknow protocol type [" << protocol_str << "] for mea [" << mea.String() << "]";
    if (protocol == ClientProtocol::FIX) {
      return true;
    }
  }
  return false;
}

auto FixTradeClientMgr::Create(
    const MarketExchangeApi& mea,
    const OrderConnectionConfig& ord_conn_cfg) -> FixTradeClientPtr {
  auto exchange = base::market::ExchangeTypeToString(mea.exchange);
  bool enabled = false;
  if (ord_conn_cfg.has_use_fix_api()) {
    enabled = ord_conn_cfg.use_fix_api();
  } else {
    enabled = Enabled(mea);
  }
  if (!enabled) {
    LOG(INFO) << "fix trade api disabled for exchange [" << exchange << "]";
    return nullptr;
  }
  std::string_view auth_key_file = ord_conn_cfg.key_filepath();
  if ("Ftx" == exchange) {
    using FixTradeClient = coin2::exchange::ftx_common::api_order::fix::FixTradeClient;
    return std::make_unique<FixTradeClient>(auth_key_file);
  } else if ("Bitstamp" == exchange) {
    using FixTradeClient = coin2::exchange::bitstamp::api_order::fix::FixTradeClient;
    return std::make_unique<FixTradeClient>(auth_key_file);
  } else if ("Gdax" == exchange) {
    using FixTradeClient = coin2::exchange::gdax::api_order::fix::FixTradeClient;
    return std::make_unique<FixTradeClient>(auth_key_file);
  } else if ("Lmaxdigital" == exchange) {
    using FixTradeClient = coin2::exchange::lmax_digital::api_order::fix::FixTradeClient;
    return std::make_unique<FixTradeClient>(auth_key_file);
  } else if ("Deribit" == exchange) {
#ifdef DISABLE_REACTOR_INTEGRATION
    using FixTradeClient = coin2::exchange::deribit::api_order::fix::FixTradeClient;
#else
    using FixTradeClient = coin2::exchange::deribit::api_order::fix::FixTradeClient2;
#endif
    return std::make_unique<FixTradeClient>(auth_key_file, mea);
  } else {
    LOG(ERROR) << "unsupported exhange: [" << exchange << "]";
    return nullptr;
  }
}

}  // namespace coin2::exchange::base::order
